package com.ilearn.iodata.iolingo.service.processor;

import com.ilearn.iodata.iolingo.service.GetCollectionService;
import com.ilearn.iodata.iolingo.service.processor.core.processor.GenericAbstractGetRequestProcessor;
import com.ilearn.iodata.iolingo.service.processor.core.query.GenericJoinQuery;
import com.ilearn.iodata.iolingo.service.provider.GenericEdmProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.server.api.*;
import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.UriResourceKind;
import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Slf4j
@Service
public class GenericEntityCollectionProcessor extends GenericODataBaseProcessor implements EntityCollectionProcessor {
//public class GenericEntityCollectionProcessor extends GenericAbstractGetRequestProcessor implements GenericRequestProcessor {


    @Autowired
    GenericEdmProvider genericEdmProvider;

    @Autowired
    private GetCollectionService getCollectionService;

    @Override
    public void init(OData odata, ServiceMetadata serviceMetadata) {
        this.odata = odata;
        this.serviceMetadata = serviceMetadata;
    }

    @Override
    public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
        // 1st we have retrieve the requested EntitySet from the uriInfo object
        // (representation of the parsed service URI)
        List<UriResource> resourcePaths = uriInfo.getUriResourceParts();

        final UriResource lastItem = resourcePaths.get(resourcePaths.size() - 1);

        UriResourceKind kind = lastItem.getKind();


        UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0); // in our example, the first segment is the EntitySet
        EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();

        // $filter
        // ======== 1 ===============
        // http://localhost:8081/chinabond.svc/members?$select=first_name,last_name&$orderby=first_name%20asc,last_name%20desc&$filter=first_name%20eq%20%27Jack%27
        // filterExpression:{[first_name] EQ 'Jack'}
        // ======== 2 ===============
        // http://localhost:8081/chinabond.svc/members?$select=first_name,last_name&$orderby=first_name%20asc,last_name%20desc&$filter=first_name%20eq%20%27Jack%27%20and%20last_name%20gt%20%27abc%27
        // filterExpression:{{[first_name] EQ 'Jack'} AND {[last_name] GT 'abc'}}

        //OlingoUtil.genericSQL(uriInfo, serviceMetadata, edmEntitySet);

        GenericJoinQuery genericJoinQuery = new GenericJoinQuery(odata, uriInfo, edmEntitySet, null);

        EntityCollection entityCollection = new EntityCollection();

        genericJoinQuery.fetchEntityCollection(getCollectionService, entityCollection);

        /*String whereClause = "";
        try {
            whereClause = getFilter2WhereClause(uriInfo, edmEntitySet);
        } catch (ExpressionVisitException e) {
            throw new ODataApplicationException(e.getMessage(),409, Locale.ENGLISH);
        }

        String selectClause = OlingoUtil.getSelectClause(odata, uriInfo, edmEntitySet.getEntityType());


        String  orderbyClause = getOrderByStr(uriInfo);


        String sql = prepareHQL(selectClause, whereClause, edmEntitySet,orderbyClause);

        System.out.println("SQL:" + sql);

        EntityCollection entityCollection = getCollection(getCollectionService, edmEntitySet, sql);*/

        /*CountOption countOption = uriInfo.getCountOption();
        if (countOption != null) {
            boolean isCount = countOption.getValue();
            if (isCount) {
                String countSQL = prepareCountHQL(selectClause, whereClause, edmEntitySet);
                entityCollectionCount = getCollectionCount(getCollectionService, countSQL);
            }
        }*/

        GenericJoinQuery.EntityCount entityCount = genericJoinQuery.fetchEntityCount(getCollectionService);

        /*if (entityCount != null) {
            entityCollection.setCount(entityCount.getCount());
        }*/

        // 3rd: create a serializer based on the requested format (json)
        ODataSerializer serializer = odata.createSerializer(responseFormat);
        //ODataFormat format = ODataFormat.fromContentType(responseFormat);
        //ODataSerializer serializer = odata.createSerializer(format);

        // 4th: Now serialize the content: transform from the EntitySet object
        // to InputStream
        EdmEntityType edmEntityType = edmEntitySet.getEntityType();
        ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet)
                //.selectList(selectList)
                .build();

        //final String id = request.getRawBaseUri() + "/" + edmEntitySet.getName();


        /*EntityCollectionSerializerOptions opts =
                EntityCollectionSerializerOptions.with().id(id).contextURL(contextUrl).build();
        SerializerResult serializedContent = serializer.entityCollection(serviceMetadata, edmEntityType, entitySet, opts);
        */

        EntityCollectionSerializerOptions opts = null;

        if (entityCount != null) {
           opts = EntityCollectionSerializerOptions
                    .with().contextURL(contextUrl)
                    .count(entityCount.getCountOption())
                    .build();
           entityCollection.setCount(entityCount.getCount());
        } else {
           opts = EntityCollectionSerializerOptions
                    .with().contextURL(contextUrl)
                    .build();
        }

        SerializerResult serializerResult = serializer.entityCollection(
                this.serviceMetadata, edmEntityType, entityCollection, opts);

        populateResponseForFormat(response, responseFormat, serializerResult);
    }


}
